﻿/*************************************************
taurus协议处理控制器
author：Daixiwei
**************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace taurus.client
{
    public class SystemController
    {
        public const string              CONNECT_TOKE				= "$t";
	    public const string CONNECT_PROT_COMPRESSION	= "$pc";
	    public const string REQUEST_CMD					= "$c";
	    public const string REQUEST_GID					= "$gi";
	    public const string REQUEST_PARM				= "$p";
	    public const string REQUEST_RESULT				= "$r";

        /// <summary>
        /// pingpong
        /// </summary>
        public const int ACTION_PINGPONG = 0;
        /// <summary>
        /// 客户端请求
        /// </summary>
        public const int ACTION_REQUST_CMD = 1;
        /// <summary>
        /// 服务器事件消息
        /// </summary>
        public const int ACTION_EVENT_CMD = 2;
        /// <summary>
        /// 验证客户端
        /// </summary>
        public const int ACTION_VALIDATE = 3;

        private Dictionary<int, Action<Packet>> __requestHandlers;
        private SocketEngine _engine;
        private long _lastTime;
        private int _tempID;
        readonly List<Message> _handleList = new List<Message>();
        

        public SystemController(SocketEngine engine)
        {
            __requestHandlers = new Dictionary<int, Action<Packet>>();
            _engine = engine;
            _lastTime = DateTime.Now.Ticks;
            initRequestHandlers();
        }

        private int _getValidID()
        {
            return ++_tempID;
        }

        internal void handlePacket(Packet packet)
        {
            _lastTime = DateTime.Now.Ticks;
            var action = __requestHandlers[packet.actionID];
            action(packet);
        }

        internal void sendRequest(Message msg)
        {
            Packet packet = new Packet();
            packet.actionID = ACTION_REQUST_CMD;
            ITObject obj = TObject.newInstance();
            obj.putString(REQUEST_CMD, msg.command);
            //if (msg.useUdp)
            //{
            //    obj.putInt(CONNECT_TOKE, _engine.sessionId);
            //}
            if (msg.useText && !string.IsNullOrEmpty(msg.textParam))
            {
                try
                {
                    obj.putTObject(REQUEST_PARM, TObject.newFromJson(msg.textParam));
                }
                catch { }
            }else
            {
                if (msg.param != null)
                {
                    obj.putTObject(REQUEST_PARM, msg.param);
                }
            }

            if (msg.callback != null)
            {
                var gid = _getValidID();
                obj.putInt(REQUEST_GID, gid);
                msg.lastTime = DateTime.Now.Ticks;
                msg.gid = gid;
                lock (_handleList)
                {
                    _handleList.Add(msg);
                }
            }
            packet.parameters = obj;
            packet.useUdp = msg.useUdp;
            _engine._packetHandler.onDataWrite(packet);
        }

        internal void sendPingPong()
        {
            Packet packet = new Packet();
            packet.actionID = ACTION_PINGPONG;
            _engine._packetHandler.onDataWrite(packet);
        }

        /// <summary>
        /// 验证合法客户端
        /// </summary>
        internal void sendValidate(ITObject data)
        {
            Packet packet = new Packet();
            packet.parameters = data;
            packet.actionID = ACTION_VALIDATE;
            _engine._packetHandler.onDataWrite(packet);
        }


        void fnOperationResponse(Packet packet)
        {
            ITObject param = null;
            string textData = null;
            if (packet.parameters.containsKey(REQUEST_PARM))
            {
                param = packet.parameters.getTObject(REQUEST_PARM);
                textData = param.toJson();
            }
            var result = packet.parameters.getInt(REQUEST_RESULT);
            var gid = packet.parameters.getInt(REQUEST_GID);
            _engine.enqueueActionForDispatch(() =>
            {
                handleOperationResponse(result, gid, param,textData);
            });
        }

        void handleOperationResponse(int result, int gid, ITObject param, string text)
        {
            Message msg = null;
            int index = 0;
            int len = _handleList.Count;
            if (gid > 0)
            {
                for (int i = 0; i < len; ++i)
                {
                    if (gid == _handleList[i].gid)
                    {
                        msg = _handleList[i];
                        index = i;
                        break;
                    }
                }
            }


            if (msg != null)
            {
                if (msg.callback != null)
                {
                    var response = new MessageResponse();
                    if(result == 0)
                    {
                        msg.param = param;
                        msg.textParam = text;
                    }
                    response.messageData = msg;
                    response.returnCode = result;
                    msg.callback(response);
                }

                lock (_handleList)
                {
                    _handleList.RemoveAt(index);
                }
            }
        }

        void fnOperationEvent(Packet packet)
        {
            var cmd = packet.parameters.getString(REQUEST_CMD);
            ITObject param = null;
            string textData = null;
            if (packet.parameters.containsKey(REQUEST_PARM))
            {
                param = packet.parameters.getTObject(REQUEST_PARM);
                textData = param.toJson();
            }
            _engine.enqueueActionForDispatch(() =>
            {
                handleEvent(cmd, param,textData);
            });
        }

        private void handleEvent(string cmd, ITObject param,string text)
        {
            var msg = new Message();
            msg.command = cmd;
            msg.param = param;
            msg.textParam = text;
            if (_engine._onEvent != null)
                _engine._onEvent(msg);
        }

        void fnPingPong(Packet packet)
        {
            _engine._lagMonitor.fnPingPong();
        }

        void fnValidate(Packet packet)
        {
            var param = packet.parameters;
            int code = param.getInt(REQUEST_RESULT);
            if(code == 0)
            {
                _engine.sessionId = param.getInt(CONNECT_TOKE);
                _engine.protocolCompression = param.getInt(CONNECT_PROT_COMPRESSION);
                _engine.onValidate();
            }
            else
            {
                _engine.enqueueStatusCallback(SocketCode.Disconnect);
            }

        }
        void fnTimeOut(Packet packet)
        {
            _engine.enqueueStatusCallback(SocketCode.TimeoutDisconnect);
        }

        /// <summary>
        /// 是否超时
        /// </summary>
        public bool isTimeOut()
        {
            return (DateTime.Now.Ticks - _lastTime) / 10000000 > NetManager.ReadTimeOut;
        }

        /// <summary>
        /// 刷新最后请求时间
        /// </summary>
        public void refreshTime()
        {
            _lastTime = DateTime.Now.Ticks;
        }

        private void initRequestHandlers()
        {
            __requestHandlers[ACTION_PINGPONG] = fnPingPong;
            __requestHandlers[ACTION_VALIDATE] = fnValidate;

            __requestHandlers[ACTION_REQUST_CMD] = fnOperationResponse;
            __requestHandlers[ACTION_EVENT_CMD] = fnOperationEvent;
        }
    }
}
